#include "app_pool.h"
#include "mqueue.h"
#include "pthread.h"
#include "log.h"
#include <stdio.h>

static mqd_t mqd;                              // 消息队列描述符
static pthread_t threads[APP_POOL_THREAD_NUM]; // 线程池

/**
 * @brief 线程执行的函数
 */
void *app_pool_thread_func(void *arg)
{
    task_t task;
    while (1)
    {
        // 1.线程主动从队列中取出任务
        int size = mq_receive(mqd, (char *)&task, sizeof(task_t), 0);
        if (size > 0)
        {
            // 2.拉取到任务后，执行任务
            task.task_func(task.task_arg);
        }
        else
        {
            perror("mq_receive");
            break;
        }
    }
    return NULL;
}

/**
 * @brief 初始化线程池
 * 1.先创建队列
 * 2.创建线程池
 */
int app_pool_init()
{
    // 1.创建队列
    mq_unlink(APP_POOL_QUEUE_NAME); // 删除队列，否则如果队列已经存在，创建会失败
    // 1.创建消息队列
    struct mq_attr attr = {
        .mq_maxmsg = APP_POOL_QUEUE_MAXMSG, /* 队列最大消息数 */
        .mq_msgsize = sizeof(task_t),       /* 消息大小 */
    };

    mqd = mq_open(APP_POOL_QUEUE_NAME, O_RDWR | O_CREAT, 0666, &attr); // 队列名称一定要以/开头
    if (mqd == -1)
    {
        perror("队列创建失败");
        return -1;
    }
    log_info("队列创建成功");
    // 2.创建线程池
    for (int i = 0; i < APP_POOL_THREAD_NUM; i++)
    {
        pthread_create(&threads[i], NULL, app_pool_thread_func, NULL);
        log_info("线程池创建成功");
    }
    return 0;
}

/**
 * @brief 向线程池提交任务
 *
 */
int app_pool_submit_task(void *(*func)(void *), void *arg)
{
    task_t task = {
        .task_func = func,
        .task_arg = arg,
    };
    // 1.将任务放入队列
    int ret = mq_send(mqd, (char *)&task, sizeof(task_t), 0);
    if (ret == -1)
    {
        perror("任务提交失败");
        return -1;
    }
    log_info("任务提交成功");
    return 0;
}

/**
 * @brief 销毁线程池
 */
void app_pool_destroy()
{
    for (int i = 0; i < APP_POOL_THREAD_NUM; i++)
    {
        // 1.线程池结束
        pthread_cancel(threads[i]);
    }
    for (size_t i = 0; i < APP_POOL_THREAD_NUM; i++)
    {
        /* 等待所有线程结束 */
        pthread_join(threads[i], NULL);
    }
    log_info("线程池销毁成功");
    // 2.队列关闭
    mq_close(mqd);
    // 3.删除队列
    mq_unlink(APP_POOL_QUEUE_NAME);
    log_info("队列销毁成功");
}